#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Java混淆器
专门处理Java代码的混淆
"""

import os
import re
from typing import Dict, List, Set, Tuple
from ..builtin_config_module.builtin_config import BuiltInConfig
from ..utils_module.logger import ObfuscationLogger

class JavaObfuscator:
    """Java混淆器"""
    
    def __init__(self, config: BuiltInConfig, logger: ObfuscationLogger):
        self.config = config
        self.logger = logger
        
        # Java语法模式
        self.patterns = {
            'class': r'\b(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:final\s+)?(?:abstract\s+)?class\s+(\w+)',
            'interface': r'\b(?:public\s+|private\s+|protected\s+)?interface\s+(\w+)',
            'enum': r'\b(?:public\s+|private\s+|protected\s+)?enum\s+(\w+)',
            'method': r'\b(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:final\s+)?(?:synchronized\s+)?(?:\w+(?:\[\])?)\s+(\w+)\s*\(',
            'field': r'\b(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:final\s+)?(?:volatile\s+)?(?:\w+(?:\[\])?)\s+(\w+)\s*[;=]',
            'constant': r'\b(?:public\s+)?(?:static\s+)?final\s+\w+\s+(\w+)\s*=',
            'annotation': r'@interface\s+(\w+)',
            'package': r'\bpackage\s+([\w.]+)',
            'generic': r'<(\w+)(?:\s+extends\s+\w+)?>'
        }
        
        # Java保留关键字
        self.java_keywords = {
            'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch',
            'char', 'class', 'const', 'continue', 'default', 'do', 'double',
            'else', 'enum', 'extends', 'final', 'finally', 'float', 'for',
            'goto', 'if', 'implements', 'import', 'instanceof', 'int', 'interface',
            'long', 'native', 'new', 'package', 'private', 'protected', 'public',
            'return', 'short', 'static', 'strictfp', 'super', 'switch', 'synchronized',
            'this', 'throw', 'throws', 'transient', 'try', 'void', 'volatile',
            'while', 'true', 'false', 'null'
        }
        
        # Java基本类型
        self.java_types = {
            'byte', 'short', 'int', 'long', 'float', 'double', 'boolean', 'char',
            'String', 'Integer', 'Long', 'Double', 'Float', 'Boolean', 'Character',
            'Byte', 'Short', 'Object', 'Class', 'System', 'Thread', 'Runnable',
            'Exception', 'RuntimeException', 'Throwable', 'Error'
        }
    
    def extract_symbols(self, file_path: str) -> List[str]:
        """提取Java文件中的符号"""
        symbols = []
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            # 移除注释和字符串
            content = self._remove_comments_and_strings(content)
            
            # 提取各种类型的符号
            for symbol_type, pattern in self.patterns.items():
                if symbol_type == 'package':  # 跳过包名
                    continue
                    
                matches = re.findall(pattern, content)
                for match in matches:
                    if isinstance(match, tuple):
                        symbol = match[0] if match[0] else None
                    else:
                        symbol = match
                    
                    if symbol and self._is_valid_java_symbol(symbol):
                        symbols.append(symbol)
            
            # 去重
            symbols = list(set(symbols))
            
        except Exception as e:
            self.logger.log_error(f"提取Java符号失败: {file_path}, 错误: {str(e)}")
        
        return symbols
    
    def _remove_comments_and_strings(self, content: str) -> str:
        """移除注释和字符串，避免误提取"""
        # 移除多行注释
        content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
        # 移除单行注释
        content = re.sub(r'//.*?$', '', content, flags=re.MULTILINE)
        # 移除字符串
        content = re.sub(r'"(?:[^"\\]|\\.)*"', '""', content)
        content = re.sub(r"'(?:[^'\\]|\\.)*'", "''", content)
        
        return content
    
    def _is_valid_java_symbol(self, symbol: str) -> bool:
        """检查是否是有效的Java符号"""
        # 排除Java关键字
        if symbol in self.java_keywords:
            return False
        
        # 排除Java基本类型
        if symbol in self.java_types:
            return False
        
        # 排除Java/Android系统包前缀
        system_prefixes = [
            'java', 'javax', 'android', 'androidx', 'com.google',
            'com.android', 'org.apache', 'org.xml', 'org.w3c'
        ]
        for prefix in system_prefixes:
            if symbol.startswith(prefix):
                return False
        
        # 排除全大写（可能是常量）
        if symbol.isupper() and len(symbol) > 2:
            return False
        
        # 排除数字开头
        if symbol[0].isdigit():
            return False
        
        # 排除下划线开头（内部使用）
        if symbol.startswith('_'):
            return False
        
        # 排除main方法
        if symbol == 'main':
            return False
        
        # 排除Android生命周期方法
        lifecycle_methods = {
            'onCreate', 'onStart', 'onResume', 'onPause', 'onStop', 'onDestroy',
            'onRestart', 'onSaveInstanceState', 'onRestoreInstanceState',
            'onCreateView', 'onViewCreated', 'onActivityCreated', 'onAttach',
            'onDetach', 'onDestroyView', 'onConfigurationChanged',
            'onRequestPermissionsResult', 'onActivityResult',
            'onCreateOptionsMenu', 'onOptionsItemSelected',
            'onPrepareOptionsMenu', 'onBackPressed', 'onKeyDown', 'onKeyUp',
            'onTouchEvent', 'onTrackballEvent', 'onUserInteraction',
            'onWindowFocusChanged', 'onAttachedToWindow', 'onDetachedFromWindow',
            'onDraw', 'onMeasure', 'onLayout', 'dispatchDraw'
        }
        if symbol in lifecycle_methods:
            return False
        
        # 排除getter/setter方法
        if re.match(r'^(get|set|is)[A-Z]', symbol):
            return False
        
        # 排除序列化方法
        serialization_methods = {
            'readObject', 'writeObject', 'readResolve', 'writeReplace',
            'readExternal', 'writeExternal'
        }
        if symbol in serialization_methods:
            return False
        
        # 排除Object类的方法
        object_methods = {
            'equals', 'hashCode', 'toString', 'clone', 'finalize',
            'getClass', 'notify', 'notifyAll', 'wait'
        }
        if symbol in object_methods:
            return False
        
        return self.config.is_symbol_safe_to_obfuscate(symbol, 'java', '')[0]
    
    def obfuscate_file(self, file_path: str, symbol_map: Dict[str, str]):
        """混淆Java文件"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            original_content = content
            
            # 识别保护区域
            protected_regions = self._identify_protected_regions(content)
            
            # 按符号长度排序，优先替换长符号
            sorted_symbols = sorted(symbol_map.items(), key=lambda x: len(x[0]), reverse=True)
            
            for original, obfuscated in sorted_symbols:
                # 使用词边界确保精确替换
                pattern = r'\b' + re.escape(original) + r'\b'
                # 使用安全替换
                content = self._safe_replace(content, pattern, obfuscated, protected_regions)
            
            # 检查是否有变化
            if content != original_content:
                if not self.config.dry_run:
                    with open(file_path, 'w', encoding='utf-8') as f:
                        f.write(content)
                
                self.logger.log_file_processing(file_path, "已混淆")
            else:
                self.logger.log_file_processing(file_path, "无需混淆")
                
        except Exception as e:
            self.logger.log_error(f"混淆Java文件失败: {file_path}, 错误: {str(e)}")
    
    def _identify_protected_regions(self, content: str) -> List[Tuple[int, int]]:
        """识别不应被混淆的区域"""
        regions = []
        
        # 多行注释 /* ... */
        for match in re.finditer(r'/\*.*?\*/', content, re.DOTALL):
            regions.append((match.start(), match.end()))
        
        # 单行注释 //
        for match in re.finditer(r'//.*?$', content, re.MULTILINE):
            regions.append((match.start(), match.end()))
        
        # 字符串 "..."
        for match in re.finditer(r'"(?:[^"\\]|\\.)*"', content):
            regions.append((match.start(), match.end()))
        
        # 字符 '...'
        for match in re.finditer(r"'(?:[^'\\]|\\.)*'", content):
            regions.append((match.start(), match.end()))
        
        # 注解 @...
        for match in re.finditer(r'@\w+(?:\([^)]*\))?', content):
            regions.append((match.start(), match.end()))
        
        # import语句
        for match in re.finditer(r'import\s+[\w.]+\s*;', content):
            regions.append((match.start(), match.end()))
            
        # package语句
        for match in re.finditer(r'package\s+[\w.]+\s*;', content):
            regions.append((match.start(), match.end()))
            
        return sorted(regions)
    
    def _safe_replace(self, content: str, pattern: str, replacement: str, protected_regions: List[Tuple[int, int]]) -> str:
        """安全替换，跳过保护区域"""
        result = []
        last_pos = 0
        
        for match in re.finditer(pattern, content):
            # 检查是否在保护区域内
            in_protected = False
            for start, end in protected_regions:
                if start <= match.start() < end:
                    in_protected = True
                    break
            
            if not in_protected:
                # 添加匹配前的内容
                result.append(content[last_pos:match.start()])
                # 添加替换内容
                result.append(replacement)
                last_pos = match.end()
        
        # 添加剩余内容
        result.append(content[last_pos:])
        return ''.join(result)
    
    def extract_class_symbols(self, content: str) -> List[str]:
        """提取类符号"""
        classes = []
        patterns = [
            r'\bclass\s+(\w+)',
            r'\binterface\s+(\w+)',
            r'\benum\s+(\w+)'
        ]
        for pattern in patterns:
            matches = re.findall(pattern, content)
            for match in matches:
                if self._is_valid_java_symbol(match):
                    classes.append(match)
        return classes
    
    def extract_method_symbols(self, content: str) -> List[str]:
        """提取方法符号"""
        methods = []
        # 更精确的方法匹配模式
        pattern = r'\b(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:final\s+)?(?:synchronized\s+)?(?:\w+(?:\[\])?)\s+(\w+)\s*\([^)]*\)'
        matches = re.findall(pattern, content)
        for match in matches:
            if self._is_valid_java_symbol(match):
                methods.append(match)
        return methods
    
    def extract_field_symbols(self, content: str) -> List[str]:
        """提取字段符号"""
        fields = []
        pattern = r'\b(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:final\s+)?(?:volatile\s+)?(?:\w+(?:\[\])?)\s+(\w+)\s*[;=]'
        matches = re.findall(pattern, content)
        for match in matches:
            if self._is_valid_java_symbol(match):
                fields.append(match)
        return fields